package com.ibeeking.found.cms.b.rest.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ibeeking.found.cms.api.common.dto.GoodsPageDTO;
import com.ibeeking.found.cms.api.common.dto.PageBaseInfoDTO;
import com.ibeeking.found.cms.api.common.query.GoodsFeignPageQuery;
import com.ibeeking.found.cms.api.common.query.PageBaseInfoQuery;
import com.ibeeking.found.cms.api.feign.CmsFeignCClient;
import com.ibeeking.found.cms.api.feign.CmsGoodsFeignBClient;
import com.ibeeking.found.cms.b.rest.service.IPageBaseService;
import com.ibeeking.found.cms.b.rest.service.IPageModuleService;
import com.ibeeking.found.cms.b.rest.service.IPageSystemBaseService;
import com.ibeeking.found.cms.service.common.bo.PageBaseBO;
import com.ibeeking.found.cms.service.common.constants.enums.PageCategoryEnum;
import com.ibeeking.found.cms.service.common.constants.enums.PagePublishStatusEnum;
import com.ibeeking.found.cms.service.common.dos.PageBaseDO;
import com.ibeeking.found.cms.service.common.dos.PageComponentsGroupDO;
import com.ibeeking.found.cms.service.common.dos.PageSystemBaseDO;
import com.ibeeking.found.cms.service.common.param.PageBaseParam;
import com.ibeeking.found.cms.service.common.query.EffectiveByTypePageQuery;
import com.ibeeking.found.cms.service.common.query.PageBasePageQuery;
import com.ibeeking.found.cms.service.common.query.PageBaseQuery;
import com.ibeeking.found.cms.service.common.vo.EffectivePageVO;
import com.ibeeking.found.cms.service.common.vo.PageBaseVO;
import com.ibeeking.found.cms.service.mapper.PageBaseMapper;
import com.ibeeking.found.common.enums.PageTypeEnum;
import com.ibeeking.found.common.enums.PublishStatusEnum;
import com.ibeeking.found.common.enums.SystemEnum;
import com.ibeeking.found.common.enums.goods.GoodsChannelEnum;
import com.ibeeking.found.common.enums.goods.GoodsModuleEnum;
import com.ibeeking.found.common.enums.goods.GoodsStatusEnum;
import com.ibeeking.found.common.utils.DataUtils;
import com.ibeeking.found.common.utils.DateUtils;
import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.nematos.core.utils.SpringBeanUtil;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.data.StringUtils;
import com.ibeeking.nematos.utils.json.JsonUtils;
import com.ibeeking.nematos.utils.result.ResponseResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @ClassName PageBaseServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-05-08 16:05
 **/
@Service
public class PageBaseServiceImpl extends ServiceImpl<PageBaseMapper, PageBaseDO> implements IPageBaseService {

    @Resource
    private PageBaseMapper pageBaseMapper;
    @Resource
    private IPageModuleService pageModuleServiceImpl;
    @Resource
    private IPageSystemBaseService pageSystemBaseServiceImpl;
    @Resource
    private CmsGoodsFeignBClient cmsGoodsFeignBClient;
    @Resource
    private CmsFeignCClient cmsFeignCClient;

    @Override
    public List<PageBaseBO> list(PageBaseQuery query) {
        List<PageBaseDO> pageBaseDOs = pageBaseMapper.selectList(new LambdaQueryWrapper<PageBaseDO>()
                .eq(StringUtils.isNotBlank(query.getIndustry()), PageBaseDO::getIndustry, query.getIndustry())
                .eq(query.getCategory() != null, PageBaseDO::getCategory, query.getCategory())
                .in(Collections3.isNotEmpty(query.getIds()), PageBaseDO::getId, query.getIds())
        );
        return JsonUtils.jsonToList(pageBaseDOs, PageBaseBO.class);
    }

    @Override
    public List<PageBaseInfoDTO> pageBaseInfoList(List<PageBaseInfoQuery> queryList) {
        List<PageBaseInfoDTO> resList = new ArrayList<>();
        queryList.forEach(query -> {
                    Integer pageType = query.getPageType();
                    List<Long> ids = query.getIds();
                    if (pageType == null || Collections3.isEmpty(ids)) {
                        return;
                    }
                    if (PageTypeEnum.FUNCTION.getValue().equals(pageType)) {
                        List<PageBaseBO> list = getBean().list(new PageBaseQuery().setIds(ids));
                        if (Collections3.isNotEmpty(list)) {
                            resList.addAll(list.stream().map(x -> new PageBaseInfoDTO().setId(x.getId()).setName(x.getTitle()).setPageType(PageTypeEnum.FUNCTION.getValue())).collect(Collectors.toList()));
                        }
                    } else if (PageTypeEnum.SYSTEM.getValue().equals(pageType)) {
                        List<PageSystemBaseDO> list = pageSystemBaseServiceImpl.list(new PageBaseQuery().setIds(ids));
                        if (Collections3.isNotEmpty(list)) {
                            resList.addAll(list.stream().map(x -> new PageBaseInfoDTO().setId(x.getId()).setName(x.getTitle()).setPageType(PageTypeEnum.SYSTEM.getValue())).collect(Collectors.toList()));
                        }
                    }
                }
        );
        return resList;
    }

    @Override
    public List<PageBaseInfoDTO> pageBaseInfoListByPageType(Integer pageType) {
        List<PageBaseInfoDTO> resList = new ArrayList<>();
        if (ObjectUtil.isNull(pageType)) {
            throw BusinessException.create("页面类型不能为空!");
        }
        if (PageTypeEnum.SYSTEM.getValue().equals(pageType)) {
            List<PageSystemBaseDO> list = pageSystemBaseServiceImpl.list();
            if (Collections3.isNotEmpty(list)) {
                resList.addAll(list.stream().map(item -> new PageBaseInfoDTO()
                        .setId(item.getId())
                        .setName(item.getTitle())
                        .setPageType(PageTypeEnum.SYSTEM.getValue())
                        .setPagePath(item.getPath())
                ).collect(Collectors.toList()));
            }
        } else {
            LambdaQueryWrapper<PageBaseDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(PageBaseDO::getType, pageType);
            List<PageBaseDO> pageBaseDOs = pageBaseMapper.selectList(queryWrapper);
            List<PageBaseBO> list = JsonUtils.jsonToList(pageBaseDOs, PageBaseBO.class);
            if (Collections3.isNotEmpty(list)) {
                resList.addAll(list.stream().map(item -> new PageBaseInfoDTO()
                        .setId(item.getId())
                        .setName(item.getTitle())
                        .setPageType(PageTypeEnum.FUNCTION.getValue())
                        .setPagePath(item.getPath())
                ).collect(Collectors.toList()));
            }
        }
        return resList;
    }

    @Override
    public Page<PageBaseVO> pageList(PageBasePageQuery pageQuery) {
        LambdaQueryWrapper<PageBaseDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotBlank(pageQuery.getIndustry()), PageBaseDO::getIndustry, pageQuery.getIndustry());
        queryWrapper.eq(pageQuery.getPlatform() != null, PageBaseDO::getPlatform, pageQuery.getPlatform());
        queryWrapper.eq(pageQuery.getPublishStatus() != null, PageBaseDO::getPublishStatus, pageQuery.getPublishStatus());
        queryWrapper.eq(pageQuery.getShopId() != null, PageBaseDO::getShopId, pageQuery.getShopId());
        queryWrapper.eq(pageQuery.getCategory() != null, PageBaseDO::getCategory, pageQuery.getCategory());
        queryWrapper.eq(pageQuery.getType() != null, PageBaseDO::getType, pageQuery.getType());
        queryWrapper.like(StringUtils.isNotBlank(pageQuery.getTitle()), PageBaseDO::getTitle, pageQuery.getTitle());
        Page<PageBaseDO> pages = pageBaseMapper.selectPage(new Page<PageBaseDO>(pageQuery.getPageNum(), pageQuery.getPageSize()), queryWrapper);
        Page<PageBaseVO> pageBaseVOPage = BeanUtil.convertPage(pages, PageBaseVO.class);
        List<PageBaseVO> records = pageBaseVOPage.getRecords();
        Optional.ofNullable(records).ifPresent(list -> {
            list.forEach(x -> {
                x.setPublishStatusName(PagePublishStatusEnum.getName(x.getPublishStatus()));
                x.setTypeName(PageTypeEnum.getEnumName(x.getType()));
            });
        });
        //todo 浏览量
        return pageBaseVOPage;
    }

    @Override
    public Page<EffectivePageVO> effectiveByTypePageList(EffectiveByTypePageQuery query) {
        query.setPlatform(SystemEnum.TENANT.getValue());
        query.setPublishStatus(PublishStatusEnum.ENABLE.getValue());
        Integer type = query.getType();
        DataUtils.trueThrowException(type == null, "请选择页面类型!");
        if (PageTypeEnum.FUNCTION.getValue().equals(type)) {
            PageBasePageQuery pageBasePageQuery = BeanUtil.convertBean(query, PageBasePageQuery.class);
            Page<PageBaseVO> pageBaseVOPage = getBean().pageList(pageBasePageQuery);
            return BeanUtil.convertPage(pageBaseVOPage, EffectivePageVO.class);
        } else if (PageTypeEnum.SYSTEM.getValue().equals(type)) {
            Page<PageSystemBaseDO> pageSystemBaseDOPage = pageSystemBaseServiceImpl.pageList(query);
            return BeanUtil.convertPage(pageSystemBaseDOPage, EffectivePageVO.class);
        } else if (PageTypeEnum.GOODS.getValue().equals(type)) {
            GoodsFeignPageQuery goodsFeignPageQuery = new GoodsFeignPageQuery()
                    .setStatus(GoodsStatusEnum.ON_SHELF.getValue())
                    .setChannel(GoodsChannelEnum.GOODS.getValue())
                    .setGoodsModuleList(CollUtil.newArrayList(GoodsModuleEnum.REAL_GOODS.getValue(), GoodsModuleEnum.COUPON.getValue()));
            goodsFeignPageQuery.setPageNum(query.getPageNum());
            goodsFeignPageQuery.setPageSize(query.getPageSize());
            com.ibeeking.nematos.utils.base.page.Page<GoodsPageDTO> goodsDTOPage = Optional.ofNullable(cmsGoodsFeignBClient.feignPageList(goodsFeignPageQuery)).map(ResponseResult::getData).orElse(null);
            Page page = BeanUtil.convertBean(goodsDTOPage, Page.class);
            List<GoodsPageDTO> records = goodsDTOPage.getRecords();
            if (Collections3.isNotEmpty(records)) {
                List<EffectivePageVO> effectivePageVOList = records.stream().map(x -> {
                    EffectivePageVO effectivePageVO = new EffectivePageVO();
                    effectivePageVO.setId(x.getId());
                    effectivePageVO.setTitle(x.getName());
                    effectivePageVO.setImgUrl(x.getThumb());
                    effectivePageVO.setType(PageTypeEnum.GOODS.getValue());
                    effectivePageVO.setPrice(x.getPrice());
                    effectivePageVO.setMarkingPrice(x.getMarkingPrice());
                    effectivePageVO.setStatus(x.getStatus());
                    effectivePageVO.setStatusDesc(x.getStatusDesc());
                    effectivePageVO.setChannel(Arrays.asList(GoodsChannelEnum.GOODS.getValue()));
                    effectivePageVO.setCreateTime(x.getCreateTime());
                    return effectivePageVO;
                }).collect(Collectors.toList());
                page.setRecords(effectivePageVOList);
            }
            return page;
        } else {
            DataUtils.trueThrowException(type == null, "请选择页面类型!");
        }
        return new Page<>();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long add(PageBaseParam pageBaseParam) {
        PageBaseDO pageBaseDO = BeanUtil.convertBean(pageBaseParam, PageBaseDO.class);
        pageBaseDO.setCreateBy(UserUtils.getUserId());
        if(StringUtils.isEmpty(pageBaseParam.getIndustry())){
            pageBaseDO.setIndustry(UserUtils.getTenantIndustry());
        }
        pageBaseDO.setCreateTime(LocalDateTime.now());
        pageBaseDO.setModifyTime(LocalDateTime.now());
        String gmtStart = pageBaseParam.getGmtStart();
        if (StringUtils.isNotBlank(gmtStart)) {
            pageBaseDO.setGmtStart(DateUtils.strToLocalDateTime(gmtStart));
        }
        int count = pageBaseMapper.insert(pageBaseDO);
        if (count > 0) {
            Long id = pageBaseDO.getId();
            PageBaseDO upDo = new PageBaseDO();
            upDo.setId(id);
            upDo.setPath("pages/main/functionPage/functionPage?id=" + id);
            upDo.setModifyBy(UserUtils.getUserId());
            upDo.setModifyTime(LocalDateTime.now());
            pageBaseMapper.updateById(upDo);
        }
        return pageBaseDO.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long modify(PageBaseParam pageBaseParam) {
        PageBaseDO pageBaseDO = BeanUtil.convertBean(pageBaseParam, PageBaseDO.class);
        pageBaseDO.setModifyBy(UserUtils.getUserId());
        pageBaseDO.setModifyTime(LocalDateTime.now());
        String gmtStart = pageBaseParam.getGmtStart();
        if(StringUtils.isEmpty(pageBaseParam.getIndustry())){
            pageBaseDO.setIndustry(UserUtils.getTenantIndustry());
        }
        if (StringUtils.isNotBlank(gmtStart)) {
            pageBaseDO.setGmtStart(DateUtils.strToLocalDateTime(gmtStart));
        }
        pageBaseMapper.updateById(pageBaseDO);
        //清除缓存
        DataUtils.falseThrowException(cmsFeignCClient.removeCacheByIds(pageBaseParam.getId()).getData(), "操作失败!");
        return pageBaseDO.getId();
    }

    @Override
    public PageBaseVO view(Long id) {
        PageBaseDO pageBaseDO = pageBaseMapper.selectById(id);
        return BeanUtil.convertBean(pageBaseDO, PageBaseVO.class);
    }

    @Override
    public PageBaseBO selById(Long id) {
        PageBaseDO pageBaseDO = pageBaseMapper.selectById(id);
        return BeanUtil.convertBean(pageBaseDO, PageBaseBO.class);
    }

    @Override
    public PageBaseBO selOneByPageCategory(PageCategoryEnum pageCategoryEnum) {
        if (pageCategoryEnum == null) {
            return null;
        }
        List<PageBaseBO> list = this.list(new PageBaseQuery().setCategory(pageCategoryEnum.getValue()));
        if (pageCategoryEnum.getHasOnlyOne() && Collections3.size(list) > 1) {
            DataUtils.trueThrowException(true, "无法获取页面(页面重复)");
        }
        if (Collections3.isEmpty(list)) {
            return null;
        }
        return list.get(0);
    }

    @Override
    public Boolean canAddByPageCategory(PageCategoryEnum pageCategoryEnum) {
        if (pageCategoryEnum == null) {
            return false;
        }
        if (!pageCategoryEnum.getHasOnlyOne()) {
            return true;
        }
        Integer count = pageBaseMapper.selectCount(new LambdaQueryWrapper<PageBaseDO>().eq(PageBaseDO::getCategory, pageCategoryEnum.getValue()));
        return count == 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean changeStatus(Long id, Integer status) {
        PageBaseDO pageBaseDO = new PageBaseDO();
        pageBaseDO.setId(id);
        pageBaseDO.setPublishStatus(status);
        pageBaseDO.setModifyTime(LocalDateTime.now());
        //清除缓存
        DataUtils.falseThrowException(cmsFeignCClient.removeCacheByIds(id).getData(), "操作失败!");
        return pageBaseMapper.updateById(pageBaseDO) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean del(Long id) {
        PageBaseDO pageBaseDO = pageBaseMapper.selectById(id);
        if (pageBaseDO == null) {
            return true;
        }
        Assert.isTrue(!PagePublishStatusEnum.YES.getValue().equals(pageBaseDO.getPublishStatus()), "禁止删除发布状态下的页面!");
        //清除缓存
        DataUtils.falseThrowException(cmsFeignCClient.removeCacheByIds(id).getData(), "操作失败!");
        pageModuleServiceImpl.delByPageId(id);
        return pageBaseMapper.deleteById(id) > 0;
    }

    private PageBaseServiceImpl getBean() {
        return SpringBeanUtil.getBean(this.getClass());
    }

}
